﻿/*
 * RETRO 2012 - v2.4
 * 
 * PaRADIIT Project
 * https://sites.google.com/site/paradiitproject/
 * 
 * This software is provided under LGPL v.3 license, 
 * which exact definition can be found at the following link:
 * http://www.gnu.org/licenses/lgpl.html
 * 
 * Please, contact us for any offers, remarks, ideas, etc.
 * 
 * Copyright © RFAI, LI Tours, 2011-2012
 * Contacts : rayar@univ-tours.fr
 *            ramel@univ-tours.fr
 * 
 */

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using System.Xml.Linq;
using Microsoft.Win32;
using System.Xml;

namespace RetroGUI.typography
{
    /// <summary>
    /// Define Model Font Family Window
    /// </summary>
    public partial class ViewModelFamilyWindow : Window
    {
        // Attributs
        private XmlDataProvider provider;
        private String FontFamilyPath;
        private List<String> FontModelXMLList;
        private List<String> FontModelImageList;
        private int index;
        private XDocument xdoc = new XDocument();

        /// <summary>
        /// Constructor
        /// <param name="FontFamilyPath">Path of the selected font family.\nExistence has been validated by the calling method.</param>
        /// </summary>
        public ViewModelFamilyWindow(String FontFamilyPath)
        {
            InitializeComponent();
            this.WindowStartupLocation = WindowStartupLocation.CenterOwner;

            // Assign path of the selected font family
            this.FontFamilyPath = FontFamilyPath;

            // Set Typo provider
            this.SetProvider();

            // Load the font family
            this.LoadFontFamily();

        }

        /// <summary>
        /// Set XML Provider for typographic resources
        /// Same as in RetroGUI.typography.AddModelDataWindow
        /// </summary>
        /// 
        public void SetProvider()
        {
            this.provider = (XmlDataProvider)this.LayoutRoot.FindResource("TypoFeed");
            String typoResourcesPath = "/resources/Typographic_Resources.xml";
            this.provider.Source = new Uri(typoResourcesPath, UriKind.RelativeOrAbsolute);
            this.provider.Refresh();
        }

        /// <summary>
        /// Handler for the open Font Model button
        /// </summary>
        private void LoadFontFamily()
        {
            // Get path list of xml and associted images
            this.FontModelXMLList = new List<String>(System.IO.Directory.GetFiles(this.FontFamilyPath, "*.xml"));
            this.FontModelImageList = new List<String>(this.FontModelXMLList.Select(item => item.Replace(".xml", ".png")));
            //this.FontModelImageList = new List<string>(System.IO.Directory.GetFiles(this.FontFamilyPath, "*.png").Where(item => !item.EndsWith("bw.png")));

            this.UpdateCurrentFontModel();
        }

        /// <summary>
        /// Update current Font Model
        /// </summary>
        private void UpdateCurrentFontModel()
        {
            // Update labels
            this.ViewModelFamilyWindow_FontModelLabel.Content = this.FontModelImageList.ElementAt(this.index);
            this.ViewModelFamilyWindow_IndexLabel.Content = Convert.ToString(this.index + 1) + " / " + Convert.ToString(this.FontModelImageList.Count);

            // Update thumbnail
            BitmapImage bi = new BitmapImage();
            bi.BeginInit();
            bi.CacheOption = BitmapCacheOption.OnLoad;
            bi.UriSource = new Uri(this.FontModelImageList.ElementAt(this.index), UriKind.RelativeOrAbsolute);
            bi.EndInit();
            this.modelImage.Source = bi;
            //this.modelImage.Source = new BitmapImage(uriSource);


            // Load XML 
            xdoc = XDocument.Load(this.FontModelXMLList.ElementAt(this.index));

            // Update current Font Model attributes regarding xml feed
            this.smallCapCheckBox.IsChecked = Convert.ToBoolean(xdoc.Root.Element("Typography").Attribute("IsSmallCap").Value);
            this.typeComboBox.SelectedValue = xdoc.Root.Element("Typography").Attribute("Type").Value;
            this.alphabetComboBox.SelectedValue = xdoc.Root.Element("Typography").Attribute("Alphabet").Value;
            this.familyComboBox.SelectedValue = xdoc.Root.Element("Typography").Attribute("Family").Value;
            this.subfamilyComboBox.SelectedValue = xdoc.Root.Element("Typography").Attribute("SubFamily").Value;
            this.bodyHeightComboBox.SelectedValue = xdoc.Root.Element("Typography").Attribute("BodyHeight").Value;
            this.thicknessTextBox.Text = xdoc.Root.Element("Typography").Attribute("Thickness").Value;

            this.transcriptionTextBox.Text = xdoc.Root.Element("Transcription").Attribute("Character").Value;
            this.unicodeTextBox.Text = xdoc.Root.Element("Transcription").Attribute("Unicode").Value;

            this.referenceTextBox.Text = xdoc.Root.Element("Description").Attribute("References").Value;
            this.graveurTextBox.Text = xdoc.Root.Element("Description").Attribute("Engraver").Value;
            this.commentTextBlock.Text = xdoc.Root.Element("Description").Attribute("Comments").Value;

            this.authorTextBox.Text = xdoc.Root.Element("Metadata").Element("Publication").Attribute("Author").Value;
            this.tileTextBox.Text = xdoc.Root.Element("Metadata").Element("Publication").Attribute("Title").Value;
            this.placeTextBox.Text = xdoc.Root.Element("Metadata").Element("Publication").Attribute("Place").Value;
            this.printerTextBox.Text = xdoc.Root.Element("Metadata").Element("Publication").Attribute("PrinterOrPublisher").Value;
            this.dateTextBox.Text = xdoc.Root.Element("Metadata").Element("Publication").Attribute("Date").Value;
            this.formatTextBox.Text = xdoc.Root.Element("Metadata").Element("Publication").Attribute("Format").Value;

            this.libraryTextBox.Text = xdoc.Root.Element("Metadata").Element("Copy").Attribute("Library").Value;
            this.callNumberTextBox.Text = xdoc.Root.Element("Metadata").Element("Copy").Attribute("CallNumber").Value;
            this.digitizationTextBox.Text = xdoc.Root.Element("Metadata").Element("Copy").Attribute("Digitization").Value;
            this.licenseTextBox.Text = xdoc.Root.Element("Metadata").Element("Copy").Attribute("Copyright").Value;
            this.cataloguerTextBox.Text = xdoc.Root.Element("Metadata").Element("Copy").Attribute("CataloguerName").Value;
        }

        /// <summary>
        /// Build normalized filename for exportation
        /// </summary>
        private String BuildFilename(String outputPath)
        {

            String filename, label, type, alphabet, family, subfamily, bodyheight;

            // Get Label
            label = this.transcriptionTextBox.Text;

            // Get Type
            type = "XX";
            if (this.typeComboBox.SelectedItem != null)
                type = ((XmlElement)this.typeComboBox.SelectedItem).Attributes["Code"].Value;

            // Get Alphabet
            alphabet = "X";
            if (this.alphabetComboBox.SelectedItem != null)
                alphabet = ((XmlElement)this.alphabetComboBox.SelectedItem).Attributes["Code"].Value;

            // Get Family
            family = "X";
            if (this.familyComboBox.SelectedItem != null)
                family = ((XmlElement)this.familyComboBox.SelectedItem).Attributes["Code"].Value;

            // Get Subfamily
            subfamily = "XX";
            if (this.subfamilyComboBox.SelectedItem != null)
                subfamily = ((XmlElement)this.subfamilyComboBox.SelectedItem).Attributes["Code"].Value;

            // Get BodyHeight
            bodyheight = "XXX";
            if (this.bodyHeightComboBox.SelectedItem != null)
                bodyheight = ((XmlElement)this.bodyHeightComboBox.SelectedItem).Attributes["Code"].Value;

            // Selection of a file name
            int cpt = 0;
            do
            {
                cpt++;
                filename = outputPath + @"\" + label + cpt + "_" + type + "_" + alphabet + "_" + family + "_" + subfamily + "_" + bodyheight + ".xml";
            }
            while (System.IO.File.Exists(filename));

            return filename;
        }
 
        /// <summary>
        /// XML ouput export 
        /// </summary>
        private void ExportToXML()
        {
            bool updateFilename = false;

            // Update Font Model attributes linked to the filename in the XML file
            if ( (xdoc.Root.Element("Typography").Attribute("Type").Value).CompareTo(Convert.ToString(this.typeComboBox.SelectedValue)) != 0 )
            {
                xdoc.Root.Element("Typography").Attribute("Type").Value = Convert.ToString(this.typeComboBox.SelectedValue);
                updateFilename = true;

            }
            if ( (xdoc.Root.Element("Typography").Attribute("Alphabet").Value).CompareTo(Convert.ToString(this.alphabetComboBox.SelectedValue)) != 0 )
            {
                xdoc.Root.Element("Typography").Attribute("Alphabet").Value = Convert.ToString(this.alphabetComboBox.SelectedValue);
                updateFilename = true;
            }
            if ( (xdoc.Root.Element("Typography").Attribute("Family").Value).CompareTo(Convert.ToString(this.familyComboBox.SelectedValue)) != 0 )
            {
                xdoc.Root.Element("Typography").Attribute("Family").Value = Convert.ToString(this.familyComboBox.SelectedValue);
                updateFilename = true;
            }
            if ( (xdoc.Root.Element("Typography").Attribute("SubFamily").Value).CompareTo(Convert.ToString(this.subfamilyComboBox.SelectedValue)) != 0 )
            {
                xdoc.Root.Element("Typography").Attribute("SubFamily").Value = Convert.ToString(this.subfamilyComboBox.SelectedValue);
                updateFilename = true;
            }
            if ( (xdoc.Root.Element("Typography").Attribute("BodyHeight").Value).CompareTo(Convert.ToString(this.bodyHeightComboBox.SelectedValue)) != 0 )
            {
                xdoc.Root.Element("Typography").Attribute("BodyHeight").Value = Convert.ToString(this.bodyHeightComboBox.SelectedValue);
                updateFilename = true;
            }
            if ((xdoc.Root.Element("Transcription").Attribute("Character").Value).CompareTo(this.transcriptionTextBox.Text) != 0)
            {
                xdoc.Root.Element("Transcription").Attribute("Character").Value = this.transcriptionTextBox.Text;
                updateFilename = true;
            }

            // Update others Font Model attributes in the XML file
            xdoc.Root.Element("Typography").Attribute("IsSmallCap").Value = Convert.ToString(this.smallCapCheckBox.IsChecked);
            xdoc.Root.Element("Typography").Attribute("Thickness").Value = this.thicknessTextBox.Text;
            xdoc.Root.Element("Transcription").Attribute("Character").Value = this.transcriptionTextBox.Text;
            xdoc.Root.Element("Transcription").Attribute("Unicode").Value = this.unicodeTextBox.Text;
            xdoc.Root.Element("Description").Attribute("References").Value = this.referenceTextBox.Text;
            xdoc.Root.Element("Description").Attribute("Engraver").Value = this.graveurTextBox.Text;
            xdoc.Root.Element("Description").Attribute("Comments").Value = this.commentTextBlock.Text;

            // Update Metadata attributes in the XML file
            xdoc.Root.Element("Metadata").Element("Publication").Attribute("Author").Value = this.authorTextBox.Text;
            xdoc.Root.Element("Metadata").Element("Publication").Attribute("Title").Value = this.tileTextBox.Text;
            xdoc.Root.Element("Metadata").Element("Publication").Attribute("Place").Value = this.placeTextBox.Text;
            xdoc.Root.Element("Metadata").Element("Publication").Attribute("PrinterOrPublisher").Value = this.printerTextBox.Text;
            xdoc.Root.Element("Metadata").Element("Publication").Attribute("Date").Value = this.dateTextBox.Text;
            xdoc.Root.Element("Metadata").Element("Publication").Attribute("Format").Value = this.formatTextBox.Text;
            xdoc.Root.Element("Metadata").Element("Copy").Attribute("Library").Value = this.libraryTextBox.Text;
            xdoc.Root.Element("Metadata").Element("Copy").Attribute("CallNumber").Value = this.callNumberTextBox.Text;
            xdoc.Root.Element("Metadata").Element("Copy").Attribute("Digitization").Value = this.digitizationTextBox.Text;
            xdoc.Root.Element("Metadata").Element("Copy").Attribute("Copyright").Value = this.licenseTextBox.Text;
            xdoc.Root.Element("Metadata").Element("Copy").Attribute("CataloguerName").Value = this.cataloguerTextBox.Text;

            // Check if filename has been changed
            String oldFilepath = this.FontModelXMLList.ElementAt(this.index);
            
            // Save xml file with appropriate instructions if filename has been changed 
            if (updateFilename)
            {
                // Build new filepath
                String newFilepath = this.BuildFilename(this.FontFamilyPath);

                // Update <Thumbnail> Name attribute
                xdoc.Root.Element("Thumbnail").Attribute("Name").Value = System.IO.Path.GetFileName(newFilepath.Replace(".xml", ".png"));

                // Save updated file
                xdoc.Save(oldFilepath);

                // Move files
                System.IO.File.Move(oldFilepath, newFilepath);
                System.IO.File.Move(oldFilepath.Replace(".xml", ".png"), newFilepath.Replace(".xml", ".png"));
                System.IO.File.Move(oldFilepath.Replace(".xml", "_bw.png"), newFilepath.Replace(".xml", "_bw.png"));

                // Update in classe Lists
                this.FontModelXMLList[this.index] = newFilepath;
                this.FontModelImageList[this.index] = newFilepath.Replace(".xml", ".png");

                // Update label
                this.ViewModelFamilyWindow_FontModelLabel.Content = newFilepath;
            }
            else
            {
                xdoc.Save(oldFilepath);
            }

            System.Windows.MessageBox.Show("The model has been updated.", "Notification", MessageBoxButton.OK, MessageBoxImage.Information);
        }


        #region Events Handlers

        /// <summary>
        /// Handler for the open Font Model button
        /// </summary>
        private void ViewModelFamilyWindow_Open_Button_Click(object sender, RoutedEventArgs e)
        {
            // Open Show Image Dialog
            OpenFileDialog ofd = new OpenFileDialog();
            ofd.InitialDirectory = this.FontFamilyPath;
            ofd.Filter = "png Files|*.png|All Files|*.*";
            bool result = (bool)ofd.ShowDialog();
            bool correctResult = false;

            // Workaround to impose the user to stay in the current Font Family Directory
            while (result && !correctResult)
            {
                if ((System.IO.Path.GetDirectoryName(ofd.FileName)).CompareTo(this.FontFamilyPath) != 0)
                {
                    MessageBox.Show("Please select an Font Model in the current Font Family Directory.", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
                    result = (bool)ofd.ShowDialog();
                }
                else 
                {
                    correctResult = true;
                }
            }

            // If valid file
            if (result && (ofd.SafeFileName.Length != 0))
            {

                // Get png correct name
                String currentModel = ofd.FileName.Replace("_bw.png", ".png");

                // Get index in the images list
                int tmp = this.FontModelImageList.IndexOf(currentModel);

                // Update index
                this.index = (tmp != -1) ? tmp : this.index;

                // Update window
                this.UpdateCurrentFontModel();
            }
        }

        /// <summary>
        /// Handler for the previous Font Model button
        /// </summary>
        private void ViewModelFamilyWindow_Previous_Button_Click(object sender, RoutedEventArgs e)
        {
            // Decrease index
            if (index > 0)
                index--;

            // Update window
            this.UpdateCurrentFontModel();
        }

        /// <summary>
        /// Handler for the next Font Model button
        /// </summary>
        private void ViewModelFamilyWindow_Next_Button_Click(object sender, RoutedEventArgs e)
        {
            // Increase index
            if (index < this.FontModelXMLList.Count - 1)
                index++;

            // Update window
            this.UpdateCurrentFontModel();
        }
        
        /// <summary>
        /// Handler for the Save Font Model button
        /// </summary>
        private void ViewModelFamilyWindow_Save_Button_Click(object sender, RoutedEventArgs e)
        {
            this.ExportToXML();
        }

        /// <summary>
        /// Handler for the Expander
        /// </summary>
        private void ViewModelFamilyWindow_Expander_Change(object sender, RoutedEventArgs e)
        {
            if (this.ViewModelFamilyWindow_Expander.IsExpanded)
                this.Height += 350;
            else
                this.Height -= 350;
        }

        #endregion
    }
}
